package com.mall.common.trace;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class TraceAspect {

    private final ObjectMapper objectMapper;

    /**
     * 定义切点 - 所有Controller类的方法
     */
    @Pointcut("execution(* com.mall..*.controller..*.*(..))")
    public void controllerPointcut() {
    }

    /**
     * 定义切点 - 所有带有@TracedMethod注解的方法
     */
    @Pointcut("@annotation(com.mall.common.trace.TracedMethod)")
    public void tracedMethodPointcut() {
    }

    /**
     * 环绕通知 - 记录Controller方法的调用信息
     */
    @Around("controllerPointcut()")
    public Object traceControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        return traceMethod(joinPoint, "controller");
    }

    /**
     * 环绕通知 - 记录带有@TracedMethod注解的方法调用信息
     */
    @Around("tracedMethodPointcut()")
    public Object traceAnnotatedMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        return traceMethod(joinPoint, "traced");
    }

    /**
     * 记录方法调用信息
     */
    private Object traceMethod(ProceedingJoinPoint joinPoint, String type) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String className = signature.getDeclaringType().getSimpleName();
        String methodName = signature.getName();
        String operationName = className + "." + methodName;

        // 设置操作名称
        TraceUtil.setOperationName(operationName);

        // 记录请求参数
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            try {
                TraceUtil.setTag("params", objectMapper.writeValueAsString(args));
            } catch (JsonProcessingException e) {
                log.warn("序列化参数异常", e);
            }
        }

        // 记录开始信息
        long startTime = System.currentTimeMillis();
        TraceUtil.info("开始执行 " + type + " 方法: " + operationName);

        Object result;
        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 计算执行时间
            long elapsedTime = System.currentTimeMillis() - startTime;
            TraceUtil.setTag("executionTime", elapsedTime + "ms");

            // 记录返回结果
            if (result != null) {
                try {
                    // 为避免记录过大的返回值，这里可以做一些限制
                    String resultStr = objectMapper.writeValueAsString(result);
                    if (resultStr.length() > 1000) {
                        resultStr = resultStr.substring(0, 1000) + "...";
                    }
                    TraceUtil.setTag("result", resultStr);
                } catch (JsonProcessingException e) {
                    log.warn("序列化结果异常", e);
                }
            }

            // 记录结束信息
            TraceUtil.info("结束执行 " + type + " 方法: " + operationName + ", 耗时: " + elapsedTime + "ms");
            return result;
        } catch (Throwable t) {
            // 记录异常信息
            TraceUtil.error("执行 " + type + " 方法异常: " + t.getMessage());
            TraceUtil.setTag("exception", t.getClass().getName());
            throw t;
        }
    }
} 